package com.sr.recitewords.exception;

import com.alibaba.fastjson.JSON;
import com.sr.recitewords.common.enums.ExpCodeEnum;
import com.sr.recitewords.common.vo.GeneralResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.PersistenceException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.slf4j.MDC;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.Arrays;
import java.util.List;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    //    @ExceptionHandler(value = Exception.class)
//    @ResponseBody
//    public Object handleException(Exception e, HttpServletRequest request) {
//        JSONObject status = new JSONObject();
//
//        // 针对业务参数异常的处理
//        if (e instanceof BusinessParamCheckingException) {
//            status.put(ExceptionConstants.GLOBAL_RETURNS_CODE, ((BusinessParamCheckingException) e).getCode());
//            status.put(ExceptionConstants.GLOBAL_RETURNS_DATA, ((BusinessParamCheckingException) e).getData());
//            return status;
//        }
//
//        //针对业务运行时异常的处理
//        if (e instanceof BusinessRunTimeException) {
//            status.put(ExceptionConstants.GLOBAL_RETURNS_CODE, ((BusinessRunTimeException) e).getCode());
//            status.put(ExceptionConstants.GLOBAL_RETURNS_DATA, ((BusinessRunTimeException) e).getData());
//            return status;
//        }
//
//        status.put(ExceptionConstants.GLOBAL_RETURNS_CODE, ExceptionConstants.SERVICE_SYSTEM_ERROR_CODE);
//        status.put(ExceptionConstants.GLOBAL_RETURNS_DATA, ExceptionConstants.SERVICE_SYSTEM_ERROR_MSG);
//        log.error("Global Exception Occured => url : {}, msg : {}", request.getRequestURL(), e.getMessage());
//        /**
//         * create by: qiankunpingtai
//         * create time: 2019/4/18 17:41
//         * 这里输出完整的堆栈信息，否则有些异常完全不知道哪里出错了。
//         */
//        log.error("Global Exception Occured => url : {}", request.getRequestURL(), e);
//        e.printStackTrace();
//        return status;
//    }
    private static final Logger logger = LogManager.getLogger("ProjectLogAspect");

    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public GeneralResult<?> errorHandler(Exception ex) {
        String resultCode;
        StringBuilder errMsg = new StringBuilder();
        if (ex instanceof HttpRequestMethodNotSupportedException) {
            resultCode = "" + ExpCodeEnum.MISSING_SUPPORTED_METHODS.getCode();
            errMsg = new StringBuilder("不支持当前请求方式！请使用 " + Arrays.toString(((HttpRequestMethodNotSupportedException) ex).getSupportedMethods()) + " 方式请求");
        } else if (ex instanceof MissingServletRequestParameterException) {
            resultCode = "" + ExpCodeEnum.MISSING_REQUIRED_ARGUMENTS.getCode();
            errMsg = new StringBuilder("缺少请求参数！ [" + ((MissingServletRequestParameterException) ex).getParameterType() + "]" + ((MissingServletRequestParameterException) ex).getParameterName());
        } else if (ex instanceof MethodArgumentNotValidException) {
            resultCode = "" + ExpCodeEnum.INVALID_ARGUMENTS.getCode();
            BindingResult bindingResult = ((MethodArgumentNotValidException) ex).getBindingResult();
            List<ObjectError> allErrors = bindingResult.getAllErrors();
            for (ObjectError error : allErrors) {
                errMsg.append(error.getDefaultMessage()).append("\n");
            }
        } else if (ex instanceof HttpMessageNotReadableException) {
            resultCode = "" + ExpCodeEnum.REQUEST_BODY_IS_MISSING.getCode();
            errMsg = new StringBuilder("请求消息体格式错误");
        } else if (ex instanceof BizException) {
            BizException tmp = (BizException) ex;
            resultCode = tmp.getErrorCode();
            errMsg = new StringBuilder(tmp.getErrorMsg());
        } else if (ex instanceof PersistenceException) {
            // 断言抛出的异常，一般是函数入参有问题 抛出异常的地方必须在函数调用前进行参数校验
            resultCode = "500";
            errMsg = new StringBuilder("数据库异常,请联系系统维护人员");
        } else if (ex instanceof IllegalArgumentException) {
            // 断言抛出的异常，一般是函数入参有问题 抛出异常的地方必须在函数调用前进行参数校验
            resultCode = "500";
            errMsg = new StringBuilder("系统错误,请联系开发人员");
        } else {
            resultCode = "" + ExpCodeEnum.UNKNOWN_ERROR.getCode();
            errMsg = new StringBuilder("未知错误," + ex.toString());
        }

        // 记录异常到日志页面
        printProjectException("全局捕获到异常", ex);

        ex.printStackTrace();
        GeneralResult<?> respData = GeneralResult.genErrorResult(errMsg.toString(), resultCode);


        printRsp(respData);

        return respData;

    }

    public static void printProjectException(String str, Exception e) {
        StringBuilder sb = new StringBuilder();
        sb.append(str).append("\n");
        sb.append(e.toString()).append("\n");
        StackTraceElement[] trace = e.getStackTrace();
        List<StackTraceElement> list = Arrays.asList(trace);
        for (int i = 0; i < list.size(); i++) {
            StackTraceElement el = list.get(i);
            String elString = el.toString();
            if (elString.startsWith("com.jw.") && !elString.endsWith("(<generated>)")) {
                sb.append(String.format("    [TRACE %03d]", i)).append(" ").append(el.toString()).append("\n");
            }
        }
        logger.error(sb.toString());
    }

    public static String replaceAllImgBase64(String json) {
        if (json.length() > 300 * 20) {
            json = json.replaceAll("<img src=.?\\\"data:image/.+?;base64,.+?\\\">", "<img base64 json ignore>");
        }
        return json;
    }

    public static void printRsp(Object rsp) {
        if (rsp == null) {
            logger.info("rsp:null");
        } else if (rsp instanceof Void) {
        } else {
            String rspJson = JSON.toJSONString(rsp);
            rspJson = GlobalExceptionHandler.replaceAllImgBase64(rspJson);
            logger.info("rsp:" + rspJson);
        }
    }
}